﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using Microsoft.Win32;
using System.Xml.Serialization;
using System.Collections;

namespace FourPartHarmony2
{
    public partial class WindowMain : Window
    {
        //private Glass glassMain;

        private Music music = new Music();

        private List<Music> undoMusicList = new List<Music>();
        private List<Music> redoMusicList = new List<Music>();

        private string ApplicationName = "FourPartHarmony2";

        public WindowMain() {
            InitializeComponent();
            grandStaffControl.Width = 0;

            grandStaffControl.SetCursorPositionChangedDelegate(
                new GrandStaffControl.CursorPositionChangedDelegate(CursorPositionChangedDelegate));
            grandStaffControl.SetGrandStaffDrawMode(GrandStaffControl.GrandStaffDrawMode.Music);

            Title = ApplicationName;
            UpdateUI();
        }

        private void UpdateUI() {
            MenuFileNew.IsEnabled = (music.GetNumOfChords() != 0);
            grandStaffControl.UpdateChordList(music.GetChordList(), false);
            MenuFileOpen.IsEnabled = true;
            MenuFileSave.IsEnabled = (music.GetNumOfChords() != 0) && (lastSaveFPHFilePath != string.Empty);
            MenuFileSaveAs.IsEnabled = (music.GetNumOfChords() != 0);
            MenuFileOutputMidiFile.IsEnabled = (music.GetNumOfChords() != 0);
            MenuEditUndo.IsEnabled = (undoMusicList.Count != 0);
            MenuEditRedo.IsEnabled = (redoMusicList.Count != 0);
            buttonDeleteSelectedChord.IsEnabled = (music.GetNumOfChords() != 0);
            buttonPlay.IsEnabled = (music.GetNumOfChords() != 0);
            MenuPlayPlay.IsEnabled = (music.GetNumOfChords() != 0);
            MenuPlayStop.IsEnabled = (music.GetNumOfChords() != 0);
            MenuEditDeleteChord.IsEnabled = (music.GetNumOfChords() != 0);
        }

        ////////////////////////////////////////////////////////////////////////
        // イベント

        public void CursorPositionChangedDelegate(int newCursorPos, int cursorX, Chord selectedChord) {
            if (null == selectedChord) {
                textBlockVerdict.Text = "和音を選択すると、ここに配置と連結の良否が表示されます。";
            } else {
                textBlockVerdict.Text = selectedChord.GetVerdictText();
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) {
            //glassMain = new Glass(this, 26);
            //glassMain.Apply();
        }

        private void buttonAddChord_Click(object sender, RoutedEventArgs e) {
            int insertPos = 0;
            if (0 < music.GetNumOfChords()) {
                insertPos = grandStaffControl.GetCursorPos() + 1;
                if (music.GetNumOfChords() < insertPos) {
                    insertPos = music.GetNumOfChords();
                }
            }

            var w = new WindowChooseChord(this, music, insertPos);
            w.ShowDialog();
        }

        private void MenuFileExit_Click(object sender, RoutedEventArgs e) {
            Close();
        }

        private void MenuHelpAbout_Click(object sender, RoutedEventArgs e) {
            var w = new WindowAboutBox();
            w.ShowDialog();
        }

        private void FormDragDrop(object sender, System.Windows.Forms.DragEventArgs e) {
            string[] paths = e.Data.GetData(System.Windows.Forms.DataFormats.FileDrop) as string[];

            LoadFphFile(paths[0]);
        }

        private void exitToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            System.Windows.Forms.Application.Exit();
        }

        private void tempoToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            var w = new WindowTempo(music.Tempo);
            var dr = w.ShowDialog();
            if (true == dr) {
                music.Tempo = w.Tempo;
            }
        }

        private void undoToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            if (undoMusicList.Count == 0) {
                return;
            }

            redoMusicList.Add(music);
            music = null;
            music = undoMusicList.ElementAt(undoMusicList.Count - 1);
            undoMusicList.RemoveAt(undoMusicList.Count - 1);

            music.AllCheckVaridityAndUpdateFunction();

            UpdateUI();
        }

        private void redoToolStripMenuItem1_Click(object sender, RoutedEventArgs e) {
            if (redoMusicList.Count == 0) {
                return;
            }

            undoMusicList.Add(music);
            music = null;
            music = redoMusicList.ElementAt(redoMusicList.Count - 1);
            redoMusicList.RemoveAt(redoMusicList.Count - 1);

            music.AllCheckVaridityAndUpdateFunction();

            UpdateUI();
        }

        private void buttonPlay_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() < 1) {
                return;
            }

            MidiManager mm = music.ToMidiFile();
            mm.PlayNow();
        }

        private void stopToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            MidiManager.Stop();
        }

        public void InsertChordToMusic(int insertPos, Chord chord) {
            // 変更前のMusicをコピーしてアンドゥバッファに入れる。
            // リドゥバッファを空にする。
            // Musicに和音を挿入。
            // grandStaffControl カーソル位置を進める。
            // grandStaffControlを再描画。
            undoMusicList.Add(music.DeepCopy());
            redoMusicList.Clear();

            music.Insert(insertPos, chord);

            grandStaffControl.IncrementCursorPos();
            UpdateUI();
        }

        private void buttonDeleteSelectedChord_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() < 1) {
                return;
            }
            undoMusicList.Add(music.DeepCopy());
            redoMusicList.Clear();
            music.DeleteChordAt(grandStaffControl.GetCursorPos());
            grandStaffControl.DecrementCursorPos();

            UpdateUI();
        }

        private string AskPath(bool bReadFile, string filter) {
            string ret = string.Empty;

            if (bReadFile) {
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.ReadOnlyChecked = true;
                ofd.Multiselect = false;
                ofd.Filter = filter;
                ofd.CheckPathExists = true;
                ofd.CheckFileExists = true;
                bool? dr = ofd.ShowDialog();
                if (true == dr) {
                    ret = ofd.FileName;
                }
            } else {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Filter = filter;
                sfd.CheckPathExists = false;
                sfd.CheckFileExists = false;
                bool? dr = sfd.ShowDialog();
                if (true == dr) {
                    ret = sfd.FileName;
                }
            }

            return ret;
        }

        private void saveMidiToolStripMenuItem1_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() < 1) {
                return;
            }

            string writeFilePath = AskPath(false, "MIDI files (*.mid)|*.mid");
            if (string.Empty == writeFilePath) {
                return;
            }

            MidiManager mm = music.ToMidiFile();
            try {
                using (BinaryWriter bw = new BinaryWriter(File.Open(writeFilePath, FileMode.Create))) {
                    mm.Write(bw);
                }
            } catch (System.Exception ex) {
                Console.WriteLine(ex.ToString());
            }
        }

        string lastSaveFPHFilePath = string.Empty;

        /// <summary>
        /// 保存 XMLバージョン
        /// </summary>
        private bool TrySave2(string path) {
            bool result = false;
            try {
                var musicSave = new MusicSave(music);
                var s = new XmlSerializer(typeof(MusicSave));
                using (TextWriter w = new StreamWriter(File.Open(path, FileMode.Create))) {
                    s.Serialize(w, musicSave);
                }
                lastSaveFPHFilePath = path;
                result = true;
            } catch (System.Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            return result;
        }

        /// <summary>
        /// 読み出し XMLバージョン
        /// </summary>
        private bool TryLoad2(string path) {
            bool result = false;
            try {
                var s = new XmlSerializer(typeof(MusicSave));
                using (TextReader r = new StreamReader(File.Open(path, FileMode.Open))) {
                    MusicSave ms = (MusicSave)s.Deserialize(r);

                    if (null != ms) {
                        music = null;
                        music = ms.ToMusic();
                        result = true;
                    }
                }
                lastSaveFPHFilePath = path;
            } catch (System.Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            return result;
        }

        private void saveAsToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() < 1) {
                return;
            }

            string writeFilePath = AskPath(false, "FourPartHarmony Files (*.fph)|*.fph");
            if (string.Empty == writeFilePath) {
                return;
            }

            bool result = TrySave2(writeFilePath);
            if (result) {
                this.Title = writeFilePath + " FourPartHarmony";
            }
            UpdateUI();
        }

        private void saveToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            if (string.Empty == lastSaveFPHFilePath) {
                saveAsToolStripMenuItem_Click(sender, e);
                return;
            }

            TrySave2(lastSaveFPHFilePath);
        }

        private void openToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            string readFilePath = AskPath(true, "FourPartHarmony Files|*.fph");
            if (string.Empty == readFilePath) {
                return;
            }

            LoadFphFile(readFilePath);
        }

        public void LoadFphFile(string path) {
            bool result = TryLoad2(path);
            if (result) {
                this.Title = path + " " + ApplicationName;
            }
            UpdateUI();
        }

        private bool TrySaveMusicXML(string path) {
            bool result = false;
            try {
                var musicSave = new MusicSave(music);

                using (TextWriter w = new StreamWriter(File.Open(path, FileMode.Create))) {
                    musicSave.ExportAsMusicXml(w);
                }
                result = true;
            } catch (System.Exception ex) {
                Console.WriteLine(ex.ToString());
            }
            return result;
        }
        
        /// <summary>
        /// MusicXML形式で出力する
        /// </summary>
        private void saveMusicXmlToolStripMenuItem1_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() < 1) {
                return;
            }

            string writeFilePath = AskPath(false, "MusicXML Files (*.xml)|*.xml");
            if (string.Empty == writeFilePath) {
                return;
            }

            bool result = TrySaveMusicXML(writeFilePath);
            if (!result) {
                MessageBox.Show(string.Format("ファイル保存失敗: {0}", writeFilePath));
            }
        }

        private void fourPartHarmonyWebToolStripMenuItem_Click(object sender, RoutedEventArgs e) {
            try {
                System.Diagnostics.Process.Start("http://code.google.com/p/fourpartharmony/");
            } catch (System.ComponentModel.Win32Exception) {
            }
        }

        private void MenuFileNew_Click(object sender, RoutedEventArgs e) {
            if (music.GetNumOfChords() != 0) {
                undoMusicList.Add(music.DeepCopy());
            }
            redoMusicList.Clear();
            music = null;
            music = new Music();

            lastSaveFPHFilePath = string.Empty;
            this.Title = ApplicationName;

            UpdateUI();
        }

        private void Window_DragEnter(object sender, DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
                e.Effects = DragDropEffects.Copy;
            } else {
                e.Effects = DragDropEffects.None;
            }
        }

        private void Window_Drop(object sender, DragEventArgs e) {
            string[] paths = e.Data.GetData(DataFormats.FileDrop) as string[];

            LoadFphFile(paths[0]);
        }

    }
}
